#!BPY

# """
# Name: 'TGT'
# Blender: 246
# Group: 'Export'
# Tooltip: 'Export objects selected in the current scene to a simple geometry-topology format (tgt)'
# """

# The script exports selected meshes of the active scene to tgt format 
# (Textual Geometry and Topology). 
# What's exported are vertices, their normal vectors and colors 
# (while rendering the color of a vertex might substitute some parameters 
# of its material), materials (represented by diffuse and specular 
# components, and shininess value) and triangles.
# 
# All of the data is stored in a text form.
#
# todo 1: there might be troubles with materials in scenes, in which some materials
# have been appended from other blend files
# todo 2: I am not sure how it is done now, but it might be worthwhile to center 
# the mesh around (0,0,0) 

import Blender
import inspect
import sys

def export(filename):

    #if not filename.lower().endswith('.tgt'):
    #    filename += '.tgt'

    scene = Blender.Scene.GetCurrent()
    #mesh_list = [ob for ob in scene.objects if ob.type=='Mesh']
    mesh_list = [ob for ob in scene.objects if ob.type=='Mesh' and ob.sel]
                                                            # export only selected objects
    materials = {}
    vcount = 0
    cvcount = 0
    mcount = 0
    tcount = 0
    ctcount = 0
    voffset = [0]
    cvoffset = [0]

    print "\n"
    print "Export to TGT starts"

    # count two numbers: an amount of non-coloured and coloured vertices in all meshes
    for ob in mesh_list:
        mesh = ob.getData(name_only=False, mesh=True)
        if mesh.vertexColors:
            cvcount = cvcount + len(mesh.verts)
        else:
            vcount = vcount + len(mesh.verts)
        

    # non-coloured vertices
    try:
        file = open(filename,"w")
        file.write("vertices\n")
        file.write("%d\n" % vcount)
        file.write("co.x co.y co.z normal.x normal.y normal.z\n")
        file.close()
    except IOError, (errno, strerror):
        print 'ERROR ACCESSING FILE ', filename, ': ', strerror
        return 1

    try:
        file = open(filename,"a")
        
        for ob in mesh_list:
            mesh = ob.getData(name_only=False, mesh=True)
            #m = ob.mat.copy()
            #m.transpose()      instead of tranposing, we multiply vector*matrix
            if mesh.vertexColors == False:
                for v in mesh.verts:
                    # calculate the final position of the vertex
                    co = Blender.Mathutils.Vector(v.co.x, v.co.y, v.co.z, 1) * ob.mat
                                                            
                    #file.write('%f %f %f ' % (v.co[0] + ob.LocX, \
                    #                        v.co[1] + ob.LocY, \
                    #                        v.co[2] + ob.LocZ))
                    file.write('%f %f %f ' % (co[0], \
                                            co[1], \
                                            co[2]))
                    # todo: check if normals are unit vectors
                    file.write('%f %f %f\n' % (v.no[0], v.no[1], v.no[2]))
                
        file.close()
    except IOError, (errno, strerror):
        print 'ERROR ACCESSING FILE ', filename, ': ', strerror
        return 1

    print "Exported %d non-coloured vertices" % vcount

    # coloured vertices
    try:
        file = open(filename,"a")
        file.write("\n")
        file.write("coloured vertices\n")
        file.write("%d\n" % cvcount)
        file.write("co.x co.y co.z normal.x normal.y normal.z ")
        file.write("color.r color.g color.b color.a\n")
        file.close()
    except IOError, (errno, strerror):
        print 'ERROR ACCESSING FILE ', filename, ': ', strerror
        return 1

    if cvcount > 0:
        for ob in mesh_list:
            mesh = ob.getData(name_only=False, mesh=True)
            
            if mesh.vertexColors:
                # Because we want to attach a colour to each coloured vertex,
                # and it's possible to access colours only thru faces 
                # (not directly by reading vertex's data), we gather colors first.
                # 
                colors = {}
                for face in mesh.faces:
                    for i, v in enumerate(face.verts):
                        if v.index not in colors:
                            colors[v.index] = face.col[i]
                        else:
                            # todo: it has happened that A-component (in RGBA) 
                            # of vertex'es color was different for 2 different
                            # faces (which contained that vertex) by a value of 1,
                            # e.g. 254 and 255
                            # colors[v.index].a != face.col[i].a:
                            if colors[v.index].r != face.col[i].r or \
                            colors[v.index].g != face.col[i].g or \
                            colors[v.index].b != face.col[i].b or \
                            colors[v.index].a - face.col[i].a > 1 or \
                            colors[v.index].a - face.col[i].a < -1:
                                print "SOME VERTEX SEEMS TO HAVE 2 DIFFERENT COLORS "
                                print "AND AS FAR AS I KNOW IT SHOULD NEVER HAPPEN! \n"
                                print "ABORTING... \n"
                try:
                    
                    file = open(filename,"a")
                    for i, v in enumerate(mesh.verts):
                        if i in colors: # else -> the i-th vertex does not belong 
                                        # to any face, and we skip any
                                        # unconnected vertices
                            
                            # calculate the final position of the vertex
                            co = Blender.Mathutils.Vector(v.co.x, v.co.y, v.co.z, 1) * \
                                                                        ob.mat
                            #file.write('%f %f %f ' % (v.co[0] + ob.LocX, \
                            #                        v.co[1] + ob.LocY, \
                            #                        v.co[2] + ob.LocZ))
                            file.write('%f %f %f ' % (co[0], \
                                                    co[1], \
                                                    co[2]))
                            #todo: check if normals are unit vectors
                            file.write('%f %f %f ' % (v.no[0], v.no[1], v.no[2]))
                            file.write('%f %f %f %f\n' % (colors[i].r, colors[i].g, \
                                                          colors[i].b, colors[i].a))
                    file.close()
                except IOError, (errno, strerror):
                    print 'ERROR ACCESSING FILE ', filename, ': ', strerror
                    return 1
    
    print "Exported %d COLOURED vertices" % cvcount

    # collect materials, count non-coloured and coloured vertices
    for ob in mesh_list:
        mesh = ob.getData(name_only=False, mesh=True)
        for m in mesh.materials:
            if m != None: # the material at this position 
                          # might have been unlinked from the mesh
                if m.getName() not in materials.keys():
                    # the materials will be added in a fixed order (so they can be indexed)
                    materials[m.getName()] = mcount
                    mcount = mcount + 1

        if mesh.vertexColors:
            tc = ctcount
        else:
            tc = tcount

        tc = tc + len(mesh.faces)
        for f in mesh.faces:
            if len(f.verts) == 4:
                tc = tc + 1 # each quad will be splitted in 2 halves (triangles)
            elif len(f.verts) != 3:
                print "A FACE CONSISTING OF %d VERTICES HAS BEEN NOTICED, " % len(f.verts), \
                      "WHICH SHOULD NEVER HAPPEN! (a face has to be either a triangle or a quad) \n", \
                      "ABORTING THE EXPORT...\n" 
               
        
        if mesh.vertexColors:
            ctcount = tc
            # offsets accumulate, i.e. if you move 2 steps after 3 steps, you make
            # 5 steps all together 
            cvoffset.append(len(mesh.verts) + cvoffset[len(cvoffset)-1])
        else:
            tcount = tc
            voffset.append(len(mesh.verts) + voffset[len(voffset)-1])


    try:
        file = open(filename, "a")
        file.write("\n")
        file.write("materials\n")
        file.write("%d\n" % mcount)
        file.write("diffuse.r  diffuse.g  diffuse.b  " + \
                    "specular.r  specular.g  specular.b  " + \
                    "shininess  mode\n")

        mat = 0
        while mat < mcount:
            done = False
            for name in materials.keys():
                if materials[name] == mat:
                    m = Blender.Material.Get(name)
                    #todo delete
                    #file.write("%f %f %f %f %f %f" % (m.R, m.G, m.B, m.specR, \
                    #                                    m.specG, m.specB))
                    if m.mode & Blender.Material.Modes.VCOL_PAINT == 0:
                        file.write("%f %f %f %f %f %f %f\n" % (m.R, m.G, m.B, \
                                            m.specR, m.specG, m.specB, \
                                            128-64*m.spec))
                    else:
                        file.write("%f %f %f %f %f %f %f VCOL_PAINT\n" % \
                                (m.R, m.G, m.B, m.specR, m.specG, m.specB, \
                                            128-64*m.spec))
                    # a word about the trasformation from Blender's specular degree
                    # to openGL: in Blender it's in the range [0,2] with the min 0,
                    # while in openGL it's in the range [0,128] with the min 128
                    
                    mat = mat + 1
                    done = True
                    break
            if not done:
                print "INTERNAL SCRIPT ERROR (SOME MATERIAL GOT LOST WHILE ", \
                        "PROCESSING), LINE ", inspect.getlineno(inspect.currentframe())
                return 1
        
        file.close()
    except IOError, (errno, strerror):
        print 'ERROR ACCESSING FILE ', filename, ': ', strerror
        return 1

    print "Exported %d materials" % mcount


    try:
        file = open(filename, "a")
        file.write("\n")
        file.write("triangles\n")
        file.write("%d\n" % tcount)
        file.write("vertex1 vertex2 vertex3 material\n")

        obit = 0
        for ob in mesh_list:
            mesh = ob.getData(name_only=False, mesh=True)
            if mesh.vertexColors == False:
                print "Exporting ", ob.name, "..."
                if mesh.materials != []: 
                    for f in mesh.faces:
                        v = f.verts
                        if mesh.materials[f.mat] != None: # this face has a material
                            file.write("%d %d %d " % (voffset[obit] + v[0].index, \
                                                    voffset[obit] + v[1].index, \
                                                    voffset[obit] + v[2].index))
                            file.write("%d\n" % materials[mesh.materials[f.mat].getName()])
                            if len(v) == 4:
                                file.write("%d %d %d " % (voffset[obit] + v[2].index, \
                                                        voffset[obit] + v[3].index, \
                                                        voffset[obit] + v[0].index))
                                file.write("%d\n" % materials[mesh.materials[f.mat].getName()])
                        else: # no material at this face
                            file.write("%d %d %d\n" % (voffset[obit] + v[0].index, \
                                                    voffset[obit] + v[1].index, \
                                                    voffset[obit] + v[2].index))
                            if len(v) == 4:
                                file.write("%d %d %d\n" % (voffset[obit] + v[2].index, \
                                                        voffset[obit] + v[3].index, \
                                                        voffset[obit] + v[0].index))
                else: # no materials in entire mesh
                    for f in mesh.faces:
                        v = f.verts
                        file.write("%d %d %d\n" % (voffset[obit] + v[0].index, \
                                                    voffset[obit] + v[1].index, \
                                                    voffset[obit] + v[2].index))
                        if len(v) == 4:
                            file.write("%d %d %d\n" % (voffset[obit] + v[2].index, \
                                                        voffset[obit] + v[3].index, \
                                                        voffset[obit] + v[0].index))
                obit = obit + 1

        print "Exported %d non-coloured triangles" % tcount
        
        file.write("\n")
        file.write("coloured triangles\n")
        file.write("%d\n" % ctcount)
        file.write("col_vertex1 col_vertex2 col_vertex3 material\n")

        obit = 0
        for ob in mesh_list:
            mesh = ob.getData(name_only=False, mesh=True)
            if mesh.vertexColors:
                print "Exporting ", ob.name, "..."
                if mesh.materials != []: 
                    for f in mesh.faces:
                        v = f.verts
                        if mesh.materials[f.mat] != None: # this face has a material
                            file.write("%d %d %d " % (cvoffset[obit] + v[0].index, \
                                                    cvoffset[obit] + v[1].index, \
                                                    cvoffset[obit] + v[2].index))
                            file.write("%d\n" % materials[mesh.materials[f.mat].getName()])
                            if len(v) == 4:
                                file.write("%d %d %d " % (cvoffset[obit] + v[2].index, \
                                                        cvoffset[obit] + v[3].index, \
                                                        cvoffset[obit] + v[0].index))
                                file.write("%d\n" % materials[mesh.materials[f.mat].getName()])
                        else: # no material at this face
                            file.write("%d %d %d\n" % (cvoffset[obit] + v[0].index, \
                                                    cvoffset[obit] + v[1].index, \
                                                    cvoffset[obit] + v[2].index))
                            if len(v) == 4:
                                file.write("%d %d %d\n" % (cvoffset[obit] + v[2].index, \
                                                        cvoffset[obit] + v[3].index, \
                                                        cvoffset[obit] + v[0].index))
                else: # no materials in the entire mesh
                    for f in mesh.faces:
                        v = f.verts
                        file.write("%d %d %d\n" % (cvoffset[obit] + v[0].index, \
                                                    cvoffset[obit] + v[1].index, \
                                                    cvoffset[obit] + v[2].index))
                        if len(v) == 4:
                            file.write("%d %d %d\n" % (cvoffset[obit] + v[2].index, \
                                                        cvoffset[obit] + v[3].index, \
                                                        cvoffset[obit] + v[0].index))
                obit = obit + 1
        file.close()       
    except IOError, (errno, strerror):
        print 'ERROR ACCESSING FILE ', filename, ': ', strerror
        return 1
    
    print "Exported %d coloured triangles" % ctcount
    
    

    print "Export to TGT ended"
    print "\n"
    return 0




def main():
    Blender.Window.FileSelector(export, 'Export to TGT', Blender.sys.makename(ext='.tgt'))




if __name__=='__main__':
    #export('c')
    main()

